//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#if (BSP_TYPE == BSP_SMDK2443)

#elif (BSP_TYPE == BSP_SMDK2450)
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
#endif

// Copyright (c) 2002 BSQUARE Corporation.  All rights reserved.
// DO NOT REMOVE --- BEGIN EXTERNALLY DEVELOPED SOURCE CODE ID 40973--- DO NOT REMOVE

// SDHC controller driver implementation

#if (BSP_TYPE == BSP_SMDK2443)
#include "SDCardDDK.h"

#elif (BSP_TYPE == BSP_SMDK2450)
#include "../../../SDDriver_INC/SDCardDDK.h"
#endif
 //[david.modify] 2008-09-20 15:34
 #include <dbgmsg_david.h>

#include "SDHC.h"


#ifndef SHIP_BUILD
#define STR_MODULE _T("CSDHCBase::")
#define SETFNAME(name) LPCTSTR pszFname = STR_MODULE name _T(":")
#else
#define SETFNAME(name)
#endif

#ifdef DEBUG
#define MAKE_OPTION_STRING(x) _T(#x)

const LPCTSTR CSDHCBase::sc_rgpszOptions[SDHCDSlotOptionCount] = {
    MAKE_OPTION_STRING(SDHCDSetSlotPower),
    MAKE_OPTION_STRING(SDHCDSetSlotInterface),
    MAKE_OPTION_STRING(SDHCDEnableSDIOInterrupts),
    MAKE_OPTION_STRING(SDHCDDisableSDIOInterrupts),
    MAKE_OPTION_STRING(SDHCDAckSDIOInterrupt),
    MAKE_OPTION_STRING(SDHCDGetWriteProtectStatus),
    MAKE_OPTION_STRING(SDHCDQueryBlockCapability),
    MAKE_OPTION_STRING(SDHCDSetClockStateDuringIdle),
    MAKE_OPTION_STRING(SDHCDSetSlotPowerState),
    MAKE_OPTION_STRING(SDHCDGetSlotPowerState),
    MAKE_OPTION_STRING(SDHCDWakeOnSDIOInterrupts),
    MAKE_OPTION_STRING(SDHCDGetSlotInfo),
#if (BSP_TYPE == BSP_SMDK2443)

#elif (BSP_TYPE == BSP_SMDK2450)
    MAKE_OPTION_STRING(SDHCDSetSlotInterfaceEx),    
#endif
};
#endif


CSDHCBase::CSDHCBase(
    ) 
: m_regDevice()
{    
  m_hBusAccess = NULL;
  m_cSlots = 0;
  m_pSlots = NULL;
  m_pSlotInfos = NULL;
  m_pHCDContext = NULL;
  m_interfaceType = InterfaceTypeUndefined;
  m_dwBusNumber = INVALID_BUS_NUMBER;
  m_hISRHandler = NULL;
  m_dwSysIntr = SYSINTR_UNDEFINED;
  m_dwPriority = 0;
  m_hevInterrupt = NULL;
  m_htIST = NULL;
  m_cpsCurrent = D0;

  m_fHardwareInitialized = FALSE;
  m_fRegisteredWithBusDriver = FALSE;
  m_fDriverShutdown = FALSE;
  m_fInterruptInitialized = FALSE;
}


CSDHCBase::~CSDHCBase(
    )
{
  // We call PreDeinit just in case we are not being destroyed by
  // a call to SHC_PreDeinit.
  PreDeinit();

  if (m_fHardwareInitialized) {
    DeinitializeHardware();
  }

  if (m_pHCDContext) {
    // Cleanup the host context
    SDHCDDeleteContext(m_pHCDContext);
  }

  if (m_pSlots) delete [] m_pSlots;
  if (m_pSlotInfos) LocalFree(m_pSlotInfos);
  if (m_hBusAccess) CloseBusAccessHandle(m_hBusAccess);
}


BOOL
CSDHCBase::Init(
    LPCTSTR pszActiveKey
    )
{
  BOOL fRet = FALSE;
  SD_API_STATUS status;
  HKEY    hkDevice = NULL;

  hkDevice = OpenDeviceKey(pszActiveKey);
  if (!hkDevice || !m_regDevice.Open(hkDevice, _T(""))) {
    DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHC: Failed to open device key\n")));
    goto EXIT;
  }

  // Get a handle to our parent bus.
  m_hBusAccess = CreateBusAccessHandle(pszActiveKey);
  if (m_hBusAccess == NULL) {
    DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHC: Could not get handle to parent\n")));
    goto EXIT;
  }

  m_cSlots = DetermineSlotCount();
#if (BSP_TYPE == BSP_SMDK2443)
  if (m_cSlots == 0) {
    goto EXIT;
  }
  ValidateSlotCount();
  RETAILMSG(0,(TEXT("CSDHCBase::Init  m_cSlots=%d\n"),m_cSlots));

#elif (BSP_TYPE == BSP_SMDK2450)
  if (!CheckSlotCount(m_cSlots)) {
    goto EXIT;
  }
  PREFAST_ASSERT(m_cSlots <= SDHC_MAX_SLOTS);
#endif

  m_pSlotInfos = (PSDHC_SLOT_INFO) LocalAlloc(LPTR, 
      sizeof(SDHC_SLOT_INFO) * m_cSlots);
  if (m_pSlotInfos == NULL) {
    DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHC Failed to allocate slot info objects\n")));
    goto EXIT;
  }

  status = SDHCDAllocateContext(m_cSlots, &m_pHCDContext);
  if (!SD_API_SUCCESS(status)) {
    DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHC Failed to allocate context : 0x%08X \n"),
          status));
    goto EXIT;
  }

  // Set our extension 
  m_pHCDContext->pHCSpecificContext = this;

  if (!InitializeHardware()) {
    goto EXIT;
  }
  RETAILMSG(0,(TEXT("AllocateSlotObjects\n")));
  // Allocate slot objects
  m_pSlots = AllocateSlotObjects(m_cSlots);
  if (m_pSlots == NULL) {
    DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHC Failed to allocate slot objects\n")));
    goto EXIT;
  }

  // Initialize the slots
  for (DWORD dwSlot = 0; dwSlot < m_cSlots; ++dwSlot) {
    PSDHC_SLOT_INFO pSlotInfo = &m_pSlotInfos[dwSlot];
    PCSDHCSlotBase pSlot = GetSlot(dwSlot);

    RETAILMSG(0,(TEXT("pSlot->Init\n")));
    if (!pSlot->Init(dwSlot, pSlotInfo->pucRegisters, m_pHCDContext, 
          m_dwSysIntr, m_hBusAccess, m_interfaceType, m_dwBusNumber, &m_regDevice)) {
      goto EXIT;
    }
  }

  // set the host controller name
  SDHCDSetHCName(m_pHCDContext, TEXT("HSMMC_CH0"));

  // set init handler
  SDHCDSetControllerInitHandler(m_pHCDContext, CSDHCBase::SDHCInitialize);
  // set deinit handler    
  SDHCDSetControllerDeinitHandler(m_pHCDContext, CSDHCBase::SDHCDeinitialize);
  // set the Send packet handler
  SDHCDSetBusRequestHandler(m_pHCDContext, CSDHCBase::SDHCBusRequestHandler);   
  // set the cancel I/O handler
  SDHCDSetCancelIOHandler(m_pHCDContext, CSDHCBase::SDHCCancelIoHandler);   
  // set the slot option handler
  SDHCDSetSlotOptionHandler(m_pHCDContext, CSDHCBase::SDHCSlotOptionHandler);

  // These values must be set before calling SDHCDRegisterHostController()
  // because they are used during that call.
  m_dwPriority = m_regDevice.ValueDW(SDHC_PRIORITY_KEY, 
      SDHC_CARD_CONTROLLER_PRIORITY);
  RETAILMSG(0,(TEXT("SDHCDRegisterHostController\n")));
  // now register the host controller 
  status = SDHCDRegisterHostController(m_pHCDContext);

  if (!SD_API_SUCCESS(status)) {
    DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHC Failed to register host controller: %0x08X \n"), 
          status));
    goto EXIT;
  }

  m_fRegisteredWithBusDriver = TRUE;
  fRet = TRUE;
  RETAILMSG(0,(TEXT("CSDHCBase::Init Finished.\n")));
EXIT:
  if (hkDevice) RegCloseKey(hkDevice);

  return fRet;
}


  SD_API_STATUS
CSDHCBase::Start()
{
  SD_API_STATUS status = SD_API_STATUS_INSUFFICIENT_RESOURCES;


DPSTR_R1("START");

  m_fDriverShutdown = FALSE;

  // allocate the interrupt event
  m_hevInterrupt = CreateEvent(NULL, FALSE, FALSE,NULL);

  if (NULL == m_hevInterrupt) {
    goto EXIT;
  }

  // initialize the interrupt event
  if (!InterruptInitialize (m_dwSysIntr, m_hevInterrupt, NULL, 0)) {
    goto EXIT;
  }

  m_fInterruptInitialized = TRUE;

  // create the interrupt thread for controller interrupts
 DPNHEX3(m_fInterruptInitialized);
 DPSTR_R1("CreateThread");  
  m_htIST = CreateThread(NULL, 0, ISTStub, this, 0, NULL);
  if (NULL == m_htIST) {
    goto EXIT;
  }

  for (DWORD dwSlot = 0; dwSlot < m_cSlots; ++dwSlot) {
    PCSDHCSlotBase pSlot = GetSlot(dwSlot);
    status = pSlot->Start();

    if (!SD_API_SUCCESS(status)) {
      goto EXIT;
    }
  }

  // wake up the interrupt thread to check the slot
  ::SetInterruptEvent(m_dwSysIntr);

  status = SD_API_STATUS_SUCCESS;

EXIT:
  if (!SD_API_SUCCESS(status)) {
    // Clean up
    Stop();
  }

 //[david.modify] 2008-09-22 17:35
 DPNHEX3(m_dwSysIntr);
 DPNHEX3(status); 
	
  return status;
}


  SD_API_STATUS
CSDHCBase::Stop()
{
  // Mark for shutdown
  m_fDriverShutdown = TRUE;

  if (m_fInterruptInitialized) {
    KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &m_dwSysIntr, sizeof(m_dwSysIntr),
        NULL, 0, NULL);

    InterruptDisable(m_dwSysIntr);
  }

  // Clean up controller IST
  if (m_htIST) {
    // Wake up the IST
    SetEvent(m_hevInterrupt);
    WaitForSingleObject(m_htIST, INFINITE); 
    CloseHandle(m_htIST);
    m_htIST = NULL;
  }

  // free controller interrupt event
  if (m_hevInterrupt) {
    CloseHandle(m_hevInterrupt);
    m_hevInterrupt = NULL;
  }

  for (DWORD dwSlot = 0; dwSlot < m_cSlots; ++dwSlot) {
    PCSDHCSlotBase pSlot = GetSlot(dwSlot);
    pSlot->Stop();
  }

  return SD_API_STATUS_SUCCESS;
}


SD_API_STATUS 
CSDHCBase::SlotOptionHandler(
    DWORD                 dwSlot, 
    SD_SLOT_OPTION_CODE   sdOption, 
    PVOID                 pData,
    DWORD                 cbData
    )
{
  SD_API_STATUS   status = SD_API_STATUS_SUCCESS;
  BOOL            fCallSlotsHandler = TRUE;

  Lock();
  Validate();
  PCSDHCSlotBase pSlot = GetSlot(dwSlot);

  DEBUGCHK(sdOption < dim(sc_rgpszOptions));
  DEBUGCHK(sc_rgpszOptions[sdOption] != NULL);
  DEBUGMSG(SDCARD_ZONE_INFO, (_T("CSDHCBase::SlotOptionHandler(%u, %s)\n"),
        dwSlot, sc_rgpszOptions[sdOption]));

  switch (sdOption) {
    case SDHCDSetSlotPower: {
                              if (cbData != sizeof(DWORD)) {
                                status = SD_API_STATUS_INVALID_PARAMETER;
                              }
                              break;
                            }

    case SDHCDSetSlotInterface: {
                                  if (cbData != sizeof(SD_CARD_INTERFACE)) {
                                    status = SD_API_STATUS_INVALID_PARAMETER;
                                  }
                                  break;
                                }

    case SDHCDEnableSDIOInterrupts:
    case SDHCDDisableSDIOInterrupts:
    case SDHCDAckSDIOInterrupt:
                                if (pData || cbData != 0) {
                                  status = SD_API_STATUS_INVALID_PARAMETER;
                                }
                                break;

    case SDHCDGetWriteProtectStatus: {
                                       if (cbData != sizeof(SD_CARD_INTERFACE)) {
                                         status = SD_API_STATUS_INVALID_PARAMETER;
                                       }
                                       break;
                                     }

    case SDHCDQueryBlockCapability: {
                                      if (cbData != sizeof(SD_HOST_BLOCK_CAPABILITY)) {
                                        status = SD_API_STATUS_INVALID_PARAMETER;
                                      }
                                      break;
                                    }

    case SDHCDSetSlotPowerState: {
                                   if (cbData != sizeof(CEDEVICE_POWER_STATE)) {
                                     status = SD_API_STATUS_INVALID_PARAMETER;
                                   }

                                   PCEDEVICE_POWER_STATE pcps = (PCEDEVICE_POWER_STATE) pData;

                                   if (*pcps < m_cpsCurrent) {
                                     // Move controller to higher power state initially since
                                     // it will need to be powered for the slot to access
                                     // registers.
                                     SetControllerPowerState(*pcps);
                                   }

                                   status = pSlot->SlotOptionHandler(sdOption, pData, cbData);

                                   // Set the power state based on current conditions. Note that 
                                   // the slot may have gone to a state different from what was 
                                   // requested.
                                   CEDEVICE_POWER_STATE cps = DetermineRequiredControllerPowerState();
                                   SetControllerPowerState(cps);
                                   fCallSlotsHandler = FALSE;
                                   break;
                                 }

    case SDHCDGetSlotPowerState: {
                                   if (cbData != sizeof(CEDEVICE_POWER_STATE)) {
                                     status = SD_API_STATUS_INVALID_PARAMETER;
                                   }
                                   break;
                                 }

    case SDHCDWakeOnSDIOInterrupts: {
                                      if (cbData != sizeof(BOOL)) {
                                        status = SD_API_STATUS_INVALID_PARAMETER;
                                      }
                                      break;
                                    }

    case SDHCDGetSlotInfo: {
                             if (cbData != sizeof(SDCARD_HC_SLOT_INFO)) {
                               status = SD_API_STATUS_INVALID_PARAMETER;
                             }
                             break;
                           }
#if (BSP_TYPE == BSP_SMDK2443)

#elif (BSP_TYPE == BSP_SMDK2450)
    case SDHCDSetSlotInterfaceEx: {
                                    if (cbData != sizeof(SD_CARD_INTERFACE_EX)) {
                                      status = SD_API_STATUS_INVALID_PARAMETER;
                                    }
                                  }
#endif
    default:
                                  break;
  }

  if (SD_API_SUCCESS(status) && fCallSlotsHandler) {
    // Call the slots handler to do the real work.
    status = pSlot->SlotOptionHandler(sdOption, pData, cbData);
  }

  Unlock();

  return status;
}


VOID
CSDHCBase::PowerDown(
    )
{
  Validate();

  for (DWORD dwSlot = 0; dwSlot < m_cSlots; ++dwSlot) {
    PCSDHCSlotBase pSlot = GetSlot(dwSlot);
    pSlot->PowerDown();
  }

  CEDEVICE_POWER_STATE cps = DetermineRequiredControllerPowerState();
  SetControllerPowerState(cps);
}


VOID
CSDHCBase::PowerUp(
    )
{
  Validate();

  for (DWORD dwSlot = 0; dwSlot < m_cSlots; ++dwSlot) {
    PCSDHCSlotBase pSlot = GetSlot(dwSlot);

    CEDEVICE_POWER_STATE cpsRequired = pSlot->GetPowerUpRequirement();
    if (cpsRequired < m_cpsCurrent) {
      // Move controller to higher power state initially since
      // it will need to be powered for the slot to access
      // registers.
      SetControllerPowerState(cpsRequired);
    }

    pSlot->PowerUp();
  }
}


VOID
CSDHCBase::PreDeinit(
    )
{
  if (m_fRegisteredWithBusDriver) {
    if (m_fDriverShutdown == FALSE) {
      // Deregister the host controller
      SDHCDDeregisterHostController(m_pHCDContext);
    }
    // else the bus driver itself already deregistered us.

    m_fRegisteredWithBusDriver = FALSE;
  }
}


BOOL 
CSDHCBase::InitializeHardware(
    )
{
  SETFNAME(_T("InitializeHardware"));

  DEBUGCHK(m_hBusAccess);
  DEBUGCHK(m_regDevice.IsOK());
  PREFAST_DEBUGCHK(m_pSlotInfos);
  RETAILMSG(0,(TEXT("CSDHCBase::InitializeHardware\n")));
  ValidateSlotCount();

  BOOL fRet = FALSE;
  PHYSICAL_ADDRESS PortAddress;
  DWORD inIoSpace = 0;

  // Read window information
  DDKWINDOWINFO wini;
  wini.cbSize = sizeof(wini);
  DWORD dwStatus = DDKReg_GetWindowInfo(m_regDevice, &wini);
  if (dwStatus != ERROR_SUCCESS) {
    DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Error getting window information\r\n"),
          pszFname));
    goto EXIT;
  }

  // Read ISR information
  DDKISRINFO isri;
  isri.cbSize = sizeof(isri);
  dwStatus = DDKReg_GetIsrInfo(m_regDevice, &isri);
  if (dwStatus != ERROR_SUCCESS) {
    DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Error getting ISR information\r\n"),
          pszFname));
    goto EXIT;
  }

#ifdef SET_TI_BOARD_PCI_REG
  {
    DDKPCIINFO dpi;
    dpi.cbSize = sizeof(dpi);
    DDKReg_GetPciInfo(m_regDevice, &dpi);

    DWORD RetVal;
    PCI_SLOT_NUMBER SlotNumber;
    SlotNumber.u.AsULONG = 0;
    SlotNumber.u.bits.DeviceNumber = dpi.dwDeviceNumber;
    SlotNumber.u.bits.FunctionNumber = 1;

    HalGetBusDataByOffset( PCIConfiguration,
        wini.dwBusNumber,
        SlotNumber.u.AsULONG,
        &RetVal,
        0x84,
        sizeof( RetVal ) );

    if (!(RetVal & 0x00200000)) {
      RetVal |= 0x00200000;
      HalSetBusDataByOffset( PCIConfiguration,
          wini.dwBusNumber,
          SlotNumber.u.AsULONG,
          &RetVal,
          0x84,
          sizeof( RetVal ) );
    }
  }
#endif

  // Sanity check ISR
  if (isri.dwSysintr == SYSINTR_NOP) {
    RETAILMSG(0,(TEXT("%s No sysintr specified in registry\r\n"),pszFname));
    DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s No sysintr specified in registry\r\n"),
          pszFname));
    // 08.03.23	by KYS
    // For HSMMC driver request OAL a SYSINTR instead of ststic SYSINTR mapping, Below KernelIoControl function is called.
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &(isri.dwIrq), sizeof(DWORD), &(isri.dwSysintr), sizeof(DWORD), NULL))
    {
      RETAILMSG(1, (TEXT("[HSMMC1] %s IOCTL_HAL_REQUEST_SYSINTR HSMMC1 Failed \n\r"), pszFname));
      goto EXIT;
    }
  }

  if (isri.szIsrDll[0] != 0) {
    if ( (isri.szIsrHandler[0] == 0) || (isri.dwIrq == IRQ_UNSPECIFIED) ) {
      DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Invalid installable ISR information in registry\r\n"),
            pszFname));
      goto EXIT;
    }
  }

  m_interfaceType = (INTERFACE_TYPE) wini.dwInterfaceType;
  m_dwBusNumber = wini.dwBusNumber;

  DWORD dwSlotZeroWindow;
  dwSlotZeroWindow = DetermineFirstSlotWindow(&wini);

  DEBUGCHK(dwSlotZeroWindow < wini.dwNumMemWindows);
  DEBUGCHK( (dwSlotZeroWindow + m_cSlots) <= wini.dwNumMemWindows );

  // Use the slot zero window for the ISR
  PDEVICEWINDOW pWindowSlotZero = &wini.memWindows[dwSlotZeroWindow];
  PortAddress.LowPart = pWindowSlotZero->dwBase;
  PortAddress.HighPart = 0;

  RETAILMSG(0,(TEXT("CSDHCBase::InitializeHardware go on...\n")));

  // Install an ISR, if present
  if (isri.szIsrDll[0] != 0) {
    m_hISRHandler = LoadIntChainHandler(isri.szIsrDll, isri.szIsrHandler, 
        (BYTE) isri.dwIrq);

    if (m_hISRHandler == NULL) {
      DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Error installing ISR\r\n"), pszFname));
      goto EXIT;
    } 
    else {
      GIISR_INFO  Info;
      DWORD       dwPhysAddr;

      fRet = BusTransBusAddrToStatic(m_hBusAccess, 
          (INTERFACE_TYPE) wini.dwInterfaceType,
          wini.dwBusNumber, PortAddress, pWindowSlotZero->dwLen,
          &inIoSpace, (PVOID *) &dwPhysAddr);
      if (fRet == FALSE) {
        DEBUGMSG(SDCARD_ZONE_ERROR,
            (_T("%s Error translating bus address to static address\r\n"), 
             pszFname));
        goto EXIT;
      }

      // Initialize ISR
      Info.SysIntr = isri.dwSysintr;
      Info.CheckPort = TRUE;
      Info.PortIsIO = (inIoSpace != 0);
      Info.UseMaskReg = FALSE;
      Info.PortAddr = dwPhysAddr + SDHC_SLOT_INT_STATUS;
      Info.PortSize = sizeof(USHORT);
      Info.Mask = 0xFF;

      fRet = KernelLibIoControl(m_hISRHandler, IOCTL_GIISR_INFO, &Info, 
          sizeof(Info), NULL, 0, NULL);
      if (fRet == FALSE) {
        DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Error setting up ISR\r\n"), pszFname));
        goto EXIT;
      }
    }
  }

  m_dwSysIntr = isri.dwSysintr;
  DEBUGMSG(SDCARD_ZONE_INIT, (_T("%s IRQ 0x%X mapped to SYS_INTR 0x%X\r\n"), 
        pszFname, isri.dwIrq, m_dwSysIntr));

  const DWORD dwEndWindow = dwSlotZeroWindow + m_cSlots;

  for (DWORD dwWindow = dwSlotZeroWindow; dwWindow < dwEndWindow; ++dwWindow) {
    DEBUGCHK(dwWindow < wini.dwNumMemWindows);
    PDEVICEWINDOW pWindowSD = &wini.memWindows[dwWindow];

    DEBUGMSG(SDCARD_ZONE_INIT,
        (_T("%s Base address -> 0x%x; length -> 0x%x \r\n"),
         pszFname, pWindowSD->dwBase, pWindowSD->dwLen));

    PortAddress.LowPart = pWindowSD->dwBase;
    PortAddress.HighPart = 0;

    inIoSpace = 0;
    PVOID pvRegisters;
    DEBUGCHK(pWindowSlotZero->dwLen >= sizeof(SSDHC_REGISTERS));

    RETAILMSG(0,(TEXT("BusTransBusAddrToVirtual. 0x%X\n"),PortAddress));
    fRet = BusTransBusAddrToVirtual(m_hBusAccess, 
        (INTERFACE_TYPE) wini.dwInterfaceType,
        wini.dwBusNumber, PortAddress, pWindowSD->dwLen, &inIoSpace, 
        &pvRegisters);
    if (fRet == FALSE) {
      RETAILMSG(0,(TEXT("%s error translating SD address \r\n"),pszFname));
      DEBUGMSG(SDCARD_ZONE_ERROR,
          (_T("%s error translating SD address \r\n"),
           pszFname));
      goto EXIT;
    }

    DEBUGCHK(inIoSpace == 0); // Will not work for I/O mappings.

    DWORD dwSlot = dwWindow - dwSlotZeroWindow;
    DEBUGCHK(dwSlot < m_cSlots);
    m_pSlotInfos[dwSlot].pucRegisters = (volatile UCHAR*) pvRegisters;
    m_pSlotInfos[dwSlot].dwExtraInfo = pWindowSD->dwLen;
  }

  m_fHardwareInitialized = TRUE;
  fRet = TRUE;
  RETAILMSG(0,(TEXT("CSDHCBase::InitializeHardware finished.\n")));
EXIT:
  return fRet;
}


BOOL 
CSDHCBase::DeinitializeHardware(
    )
{
  DEBUGCHK(m_hBusAccess);
  PREFAST_DEBUGCHK(m_pSlotInfos);
  ValidateSlotCount();

  for (DWORD dwSlot = 0; dwSlot < m_cSlots; ++dwSlot) {
    PVOID pvRegisters = (PVOID) m_pSlotInfos[dwSlot].pucRegisters;
    DWORD dwLen = m_pSlotInfos[dwSlot].dwExtraInfo;
    if (pvRegisters) MmUnmapIoSpace(pvRegisters, dwLen);
  }

  if (m_hISRHandler) FreeIntChainHandler(m_hISRHandler);

  return TRUE;
}

int g_ist_cnttimes=0;
  DWORD
CSDHCBase::IST()
{
  SETFNAME(_T("IST"));

  DEBUGMSG(SDCARD_ZONE_INIT, (TEXT("%s Thread Starting\n"), pszFname));

DPNHEX3(m_dwPriority);
  if (!CeSetThreadPriority(GetCurrentThread(), m_dwPriority)) {
    DEBUGMSG(SDCARD_ZONE_WARN, (TEXT("%s Failed to set CEThreadPriority\n"),
          pszFname));
  }

  while (TRUE) {
    DEBUGCHK(m_hevInterrupt);
//    DWORD dwWaitStatus = WaitForSingleObject(m_hevInterrupt, INFINITE);
    DWORD dwWaitStatus;

 //[david.modify] 2008-09-20 17:25
 dwWaitStatus = WaitForSingleObject(m_hevInterrupt, INFINITE);
//	dwWaitStatus= WaitForSingleObject(m_hevInterrupt, 100);
//	g_ist_cnttimes++;
//	DPNHEX3(g_ist_cnttimes);
 //[david.modify] 2008-09-19 22:16
  	DPSTR("CH1");
 	DPNOK(m_hevInterrupt);
	
    Validate();
   	// 08.07.11 by KYS
   	// Because the InterruptDone afer interrupt handling can clear the IRQ during interrupt handling,
   	// the InterruptDone must be here, before interrupt handling.
	InterruptDone(m_dwSysIntr);

 //[david.modify] 2008-09-19 22:47
 //
dwWaitStatus = WAIT_OBJECT_0;
DPNOK(dwWaitStatus);

    if (WAIT_OBJECT_0 != dwWaitStatus) {
      DEBUGMSG(SDCARD_ZONE_WARN, (TEXT("%s Wait Failed! 0x%08X\n"), 
            pszFname, dwWaitStatus));
      // bail out
      break;
    }
    else if (m_fDriverShutdown) {
      break;
    }
    else {
      RETAILMSG(0,(TEXT("CSDHCBase::IST()\n")));			
      HandleInterrupt();
      //InterruptDone(m_dwSysIntr);
    }
  }

  DEBUGMSG(SDCARD_ZONE_INIT, (TEXT("%s Thread Exiting\n"), pszFname));

  return 0;
}


VOID 
CSDHCBase::HandleInterrupt(
    ) 
{
  Lock();

  // Use slot zero to get the shared global interrupt register
  PCSDHCSlotBase pSlotZero = GetSlot(0);
  DWORD dwIntStatus = 0;
  dwIntStatus = pSlotZero->ReadControllerInterrupts();

  do {
    DEBUGMSG(SDHC_INTERRUPT_ZONE, (TEXT("CSDHCBase::HandleInterrupt: Slot Interrupt_Status=0x%X\n"), 
          dwIntStatus));

    for (DWORD dwSlot = 0; dwSlot < m_cSlots; ++dwSlot) {
      PCSDHCSlotBase pSlot = GetSlot(dwSlot);
#if (BSP_TYPE == BSP_SMDK2443)
      //if ( ((1 << dwSlot) & dwIntStatus) || pSlot->NeedsServicing() ) {
      pSlot->HandleInterrupt();
      //}

#elif (BSP_TYPE == BSP_SMDK2450)
			// 08.07.09 by KYS
			// It is not needed to use slot number because we use NORMAL_INT_STATUS instead of SLOT_INT_STATUS
			//if ( ((1 << dwSlot) & dwIntStatus) || pSlot->NeedsServicing() ) {
			if ( (dwIntStatus) || pSlot->NeedsServicing() ) {
        pSlot->HandleInterrupt();
      }
#endif
    }

    dwIntStatus = pSlotZero->ReadControllerInterrupts();

#if (BSP_TYPE == BSP_SMDK2443)
    if(dwIntStatus && pSlotZero->IsOnlySDIOInterrupt()) break;

#elif (BSP_TYPE == BSP_SMDK2450)
    // 08.01.28 by KYS
    // In order to prevent infinite CARD INT occuring, below code is needed because of the architecture of HSMMC on s3c2450.
    if(dwIntStatus && pSlotZero->IsOnlySDIOInterrupt()) break;       
#endif
  } while (dwIntStatus);

  //InterruptDone(m_dwSysIntr);

  Unlock();
}


DWORD
CSDHCBase::DetermineSlotCount(
    )
{
  SETFNAME(_T("DetermineSlotCount"));

  DWORD cSlots = 0;

  // Read window information
  DDKWINDOWINFO wini = { sizeof(wini) };
  DWORD dwStatus = DDKReg_GetWindowInfo(m_regDevice, &wini);
  if (dwStatus != ERROR_SUCCESS) {
    DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Error getting window information\r\n"),
          pszFname));
    goto EXIT;
  }

  cSlots = wini.dwNumMemWindows;

  if (cSlots == 0) {
    DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s There were not any reported slots.\r\n"),
          pszFname));
    goto EXIT;
  }

EXIT:
  return cSlots;
}




DWORD 
CSDHCBase::DetermineFirstSlotWindow(
    PDDKWINDOWINFO pwini
    )
{
  PREFAST_DEBUGCHK(pwini);
  DEBUGCHK(pwini->dwNumMemWindows >= m_cSlots);
  DEBUGCHK(pwini->dwNumMemWindows > 0);

  DWORD dwSlotZeroWindow = 0;

  return dwSlotZeroWindow;
}


CEDEVICE_POWER_STATE
CSDHCBase::DetermineRequiredControllerPowerState(
    )
{
#if (BSP_TYPE == BSP_SMDK2443)
  CEDEVICE_POWER_STATE cps = D4;

#elif (BSP_TYPE == BSP_SMDK2450)
  CEDEVICE_POWER_STATE cps = (CEDEVICE_POWER_STATE)D4;    
#endif
  for (DWORD dwSlot = 0; dwSlot < m_cSlots; ++dwSlot) {
    PCSDHCSlotBase pSlot = GetSlot(dwSlot);
    cps = min(cps, pSlot->GetPowerState());
  }

  return cps;
}


SD_API_STATUS
CSDHCBase::SetControllerPowerState(
    CEDEVICE_POWER_STATE cpsNew
    )
{
  if (cpsNew != m_cpsCurrent) {
    switch (cpsNew) {
      case D0:
      case D4:
        KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &m_dwSysIntr, 
            sizeof(m_dwSysIntr), NULL, 0, NULL);
        break;

      case D3:
        KernelIoControl(IOCTL_HAL_ENABLE_WAKE, &m_dwSysIntr, 
            sizeof(m_dwSysIntr), NULL, 0, NULL);
        break;
    }

    SetDevicePowerState(m_hBusAccess, cpsNew, NULL);
    m_cpsCurrent = cpsNew;
  }

  return SD_API_STATUS_SUCCESS;
}


#ifdef DEBUG
VOID 
CSDHCBase::Validate(
    )
{
  DEBUGCHK(m_regDevice.IsOK());
  DEBUGCHK(m_hBusAccess);
  ValidateSlotCount();
  DEBUGCHK(m_pSlots);
  DEBUGCHK(m_pSlotInfos);
  DEBUGCHK(m_pHCDContext);
  DEBUGCHK(m_dwBusNumber != INVALID_BUS_NUMBER);
  DEBUGCHK(m_interfaceType != InterfaceTypeUndefined);
  DEBUGCHK(m_dwSysIntr != SYSINTR_UNDEFINED);
  DEBUGCHK(VALID_DX(m_cpsCurrent));

  if (m_fRegisteredWithBusDriver && !m_fDriverShutdown) {
    DEBUGCHK(m_htIST);
    DEBUGCHK(m_fHardwareInitialized);
    DEBUGCHK(m_fInterruptInitialized);
  }
}
#endif


// Get the creation proc address and call it
PCSDHCBase
CSDHCBase::CreateSDHCControllerObject(
    LPCTSTR pszActiveKey
    )
{
  PCSDHCBase pSDHC = NULL;
  HKEY hkDevice = OpenDeviceKey(pszActiveKey);

  if (hkDevice) {
    CReg regDevice(hkDevice, _T(""));
    DEBUGCHK(regDevice.IsOK());
    TCHAR szDll[MAX_PATH];

    if (regDevice.ValueSZ(DEVLOAD_DLLNAME_VALNAME, szDll, dim(szDll))) {
      szDll[dim(szDll) - 1] = 0; // Null-terminate

      TCHAR szProc[MAX_PATH];

      if (regDevice.ValueSZ(SDHC_CREATION_PROC_KEY, szProc, dim(szProc))) {
        szProc[dim(szProc) - 1] = 0; // Null-terminate

        HMODULE hMod = LoadLibrary(szDll);
        if (hMod) {
          LPSDHC_CREATION_PROC pfnCreate = (LPSDHC_CREATION_PROC)
            GetProcAddress(hMod, szProc);
          if (pfnCreate) {
            pSDHC = (*pfnCreate)();
          }

          FreeLibrary(hMod);
        }
      }
    }

    RegCloseKey(hkDevice);
  }

  return pSDHC;
}


///////////////////////////////////////////////////////////////////////////////
//  SDHCInitialize - Initialize the the controller
//  Input:  pHCContext -  host controller context
//          
//  Output: 
//  Return: SD_API_STATUS
//  Notes:  
//          
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS CSDHCBase::SDHCInitialize(PSDCARD_HC_CONTEXT pHCContext)
{
  DEBUGMSG(SDCARD_ZONE_INIT,(TEXT("SDHCInitialize++\n")));

  PREFAST_DEBUGCHK(pHCContext);
  PCSDHCBase pController = GET_PCONTROLLER_FROM_HCD(pHCContext);
  PREFAST_DEBUGCHK(pController);
  SD_API_STATUS status = pController->Start();

  DEBUGMSG(SDCARD_ZONE_INIT,(TEXT("SDHCInitialize--\n")));

  return status;
}


///////////////////////////////////////////////////////////////////////////////
//  SDHCDeinitialize - Deinitialize the SDHC Controller
//  Input:  pHCContext - HC context
//          
//  Output: 
//  Return: SD_API_STATUS
//  Notes:  
//          
//
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS CSDHCBase::SDHCDeinitialize(PSDCARD_HC_CONTEXT pHCContext)
{
  DEBUGMSG(SDCARD_ZONE_INIT,(TEXT("SDHCDeinitialize++\n")));

  PREFAST_DEBUGCHK(pHCContext);
  PCSDHCBase pController = GET_PCONTROLLER_FROM_HCD(pHCContext);
  PREFAST_DEBUGCHK(pController);
  SD_API_STATUS status = pController->Stop();

  DEBUGMSG(SDCARD_ZONE_INIT,(TEXT("SDHCDeinitialize--\n")));

  return status;
}


///////////////////////////////////////////////////////////////////////////////
//  SDHCSDCancelIoHandler - io cancel handler 
//  Input:  pHostContext - host controller context
//          dwSlot - slot the request is going on
//          pRequest - the request to be cancelled
//          
//  Output: 
//  Return: TRUE if I/O was cancelled
//  Notes:  
//          the HC lock is taken before entering this cancel handler
//
///////////////////////////////////////////////////////////////////////////////
BOOLEAN 
CSDHCBase::SDHCCancelIoHandler(
    PSDCARD_HC_CONTEXT  pHCContext,
    DWORD               dwSlot,
    PSD_BUS_REQUEST     pRequest
    )
{
  PREFAST_DEBUGCHK(pHCContext);
  PCSDHCBase pController = GET_PCONTROLLER_FROM_HCD(pHCContext);
  PREFAST_DEBUGCHK(pController);
  return pController->CancelIoHandler(dwSlot, pRequest);
}


///////////////////////////////////////////////////////////////////////////////
//  SDHCBusRequestHandler - bus request handler 
//  Input:  pHostContext - host controller context
//          dwSlot - slot the request is going to
//          pRequest - the request
//          
//  Output: 
//  Return: SD_API_STATUS
//  Notes:  The request passed in is marked as uncancelable, this function
//          has the option of making the outstanding request cancelable    
//          returns status pending
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS 
CSDHCBase::SDHCBusRequestHandler(
    PSDCARD_HC_CONTEXT pHCContext, 
    DWORD              dwSlot, 
    PSD_BUS_REQUEST    pRequest
    ) 
{
  PREFAST_DEBUGCHK(pHCContext);
  PCSDHCBase pController = GET_PCONTROLLER_FROM_HCD(pHCContext);
  PREFAST_DEBUGCHK(pController);
  return pController->BusRequestHandler(dwSlot, pRequest);
}


///////////////////////////////////////////////////////////////////////////////
//  SDHCSlotOptionHandler - handler for slot option changes
//  Input:  pHostContext - host controller context
//          dwSlot       - the slot the change is being applied to
//          Option       - the option code
//          pData        - data associaSHC with the option
//  Output: 
//  Return: SD_API_STATUS
//  Notes:  
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS 
CSDHCBase::SDHCSlotOptionHandler(
    PSDCARD_HC_CONTEXT    pHCContext,
    DWORD                 dwSlot, 
    SD_SLOT_OPTION_CODE   sdOption, 
    PVOID                 pData,
    ULONG                 ulOptionSize
    )
{
  PCSDHCBase pController = GET_PCONTROLLER_FROM_HCD(pHCContext);
  PREFAST_DEBUGCHK(pController);
  return pController->SlotOptionHandler(dwSlot, sdOption, pData, ulOptionSize);
}


// DO NOT REMOVE --- END EXTERNALLY DEVELOPED SOURCE CODE ID --- DO NOT REMOVE

